package com.lanyou.cook.web;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.joda.time.DateTime;
import org.joda.time.Hours;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.lanyou.cook.common.Constants;
import com.lanyou.cook.datadictionary.InterfaceRunResult;
import com.lanyou.cook.entity.domain.InterfaceExecutionResult;
import com.lanyou.cook.entity.kettle.KettleSlaveServer;
import com.lanyou.cook.util.gson.GsonUtil;

/**
 * 节点运行统计相关业务控制层
 * @author 杨晨睿
 *
 */
@RestController
@RequestMapping(Constants.BASE_URL_API + "/slaveServiceStatistics")
public class SlaveServerStatisticsController {
	@PersistenceContext
	private EntityManager entityManager;
	
	//统计查询功能
	/**
	 * 根据节点ID统计该节点的相关信息
	 * @param nodeId 类型:String 待统计的节点ID
	 * @return 类型:String 返回该节点统计的相关数据
	 */
	@RequestMapping(value = "/search/countByNodeIdAndTime", produces = "application/json")
	@RequiresPermissions(value = { "nodeRunStatistics:view" })
	public String countByNodeIdAndTime(String nodeId) throws ParseException {
		
		String errorRate = getErrorRate(nodeId);
		/*Date	beginOfRunEndTime = fastDateFormat1.parse("2015-11-12 09:30:02");
		 Date	endOfRunEndTime = fastDateFormat1.parse("2015-11-12 21:49:21");*/
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.HOUR_OF_DAY, -12);
		Date now = new Date();
		Date beginOfRunEndTime = DateUtils.truncate(calendar.getTime(),Calendar.SECOND);
		
		//String b1 = fastDateFormat1.format(beginOfRunEndTime);
		
		Date endOfRunEndTime = DateUtils.ceiling(now, Calendar.SECOND);
		
		//String b2 = fastDateFormat1.format(endOfRunEndTime);
		 
		
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> cq = cb.createTupleQuery();
		
		// 构建FROM和JOIN部分
		Root<InterfaceExecutionResult> rootInterfaceExecutionResult = cq.from(InterfaceExecutionResult.class);/*
		Join<InterfaceExecutionResult, KettleSlaveServer> joinKettleSlaveServer = rootInterfaceExecutionResult.join("client");*/
		Root<KettleSlaveServer> rootKettleSlaveServer = cq.from(KettleSlaveServer.class);
		// 构建WHERE部分
		List<Predicate> predicatesList = new ArrayList<>();
		if(StringUtils.isNotBlank(nodeId)){
			predicatesList.add(cb.equal(rootInterfaceExecutionResult.get("slaveServerId"), nodeId));
			predicatesList.add(cb.equal(rootKettleSlaveServer.get("id"), nodeId));
		}
		
		predicatesList.add(cb.between(rootInterfaceExecutionResult.get("runBeginTime"), beginOfRunEndTime, endOfRunEndTime));
		cq.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
		
		// 构建SELECT部分
		cq.multiselect(rootKettleSlaveServer.get("name").alias("name"), rootKettleSlaveServer.get("hostName").alias("hostName"),
				rootKettleSlaveServer.get("port").alias("port"),rootKettleSlaveServer.get("isMaster").alias("isMaster"),
				cb.sum(rootInterfaceExecutionResult.get("runTimes")).alias("allRunTimes"),
				cb.max(rootInterfaceExecutionResult.get("runTimes")).alias("mostRunTimes"));

		// 执行查询
		TypedQuery<Tuple> q = entityManager.createQuery(cq);
		List<Tuple> queryResult = q.getResultList();
		
		
		//查询错误率
		
		JsonArray jsonDatas = new JsonArray();
		for (Tuple tuple : queryResult) {
			String name = tuple.get("name", String.class);
			String hostName = tuple.get("hostName", String.class);
			String port = tuple.get("port", String.class);
			Boolean isMaster = tuple.get("isMaster", Boolean.class);
			Number allRunTimes = tuple.get("allRunTimes", Number.class);
			Number mostRunTimes = tuple.get("mostRunTimes", Number.class);
			
			JsonObject jo = new JsonObject();
			jo.addProperty("name", name);
			jo.addProperty("hostName", hostName);
			jo.addProperty("port", port);
			jo.addProperty("isMaster", isMaster);
			if(allRunTimes != null){
				jo.addProperty("allRunTimes", allRunTimes.toString());
			}else{
				jo.addProperty("allRunTimes", 0);
			}
			jo.addProperty("errorRate", errorRate);
			if(mostRunTimes != null){
				jo.addProperty("mostRunTimes", mostRunTimes.toString());
			}else{
				jo.addProperty("mostRunTimes", 0);
			}
			jsonDatas.add(jo);
		}
		
		JsonObject jsonResult = new JsonObject();
		jsonResult.add("content", jsonDatas);
		return jsonResult.toString();
	}
	
	/**
	 * 根据节点ID统计该节点的错误率
	 * @param nodeId 类型:String 待统计的节点ID
	 * @return 类型:String 返回该节点错误率
	 */
	public String getErrorRate(String nodeId) throws ParseException{
		
		/*Date	beginOfRunEndTime = fastDateFormat1.parse("2015-11-12 09:30:02");
		 Date	endOfRunEndTime = fastDateFormat1.parse("2015-11-12 21:49:21");*/
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.HOUR_OF_DAY, -12);
		Date now = new Date();
		Date beginOfRunEndTime = DateUtils.truncate(calendar.getTime(),Calendar.SECOND);
		
		//String b1 = fastDateFormat1.format(beginOfRunEndTime);
		
		Date endOfRunEndTime = DateUtils.ceiling(now, Calendar.SECOND);
		
		//String b2 = fastDateFormat1.format(endOfRunEndTime);
		 
		
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Tuple> cq = cb.createTupleQuery();
		
		// 构建FROM和JOIN部分
		Root<InterfaceExecutionResult> rootInterfaceExecutionResult = cq.from(InterfaceExecutionResult.class);/*
		Join<InterfaceExecutionResult, KettleSlaveServer> joinKettleSlaveServer = rootInterfaceExecutionResult.join("client");*/
		Root<KettleSlaveServer> rootKettleSlaveServer = cq.from(KettleSlaveServer.class);
		// 构建WHERE部分
		List<Predicate> predicatesList = new ArrayList<>();
		if(StringUtils.isNotBlank(nodeId)){
			predicatesList.add(cb.equal(rootInterfaceExecutionResult.get("slaveServerId"), nodeId));
			predicatesList.add(cb.equal(rootKettleSlaveServer.get("id"), nodeId));
		}
		
		predicatesList.add(cb.between(rootInterfaceExecutionResult.get("runBeginTime"), beginOfRunEndTime, endOfRunEndTime));
		cq.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
		
		// 构建GROUP BY部分
		cq.groupBy(rootInterfaceExecutionResult.get("runResult"), rootInterfaceExecutionResult.get("runResult"));
		
		// 构建SELECT部分
		cq.multiselect(
				rootInterfaceExecutionResult.get("runResult").alias("runResult"),
				cb.count(rootInterfaceExecutionResult.get("id")).alias("id"));

		// 执行查询
		TypedQuery<Tuple> q = entityManager.createQuery(cq);
		List<Tuple> queryResult = q.getResultList();
		
		
		//查询错误率
		
		JsonArray jsonDatas = new JsonArray();
		for (Tuple tuple : queryResult) {
			String runResult = tuple.get("runResult", String.class);
			Number id = tuple.get("id", Number.class);
			
			JsonObject jo = new JsonObject();
			jo.addProperty("runResult", runResult);
			jo.addProperty("id", id);
			jsonDatas.add(jo);
		}
		int faildCount = 0;
		int successCount = 0;
		int ExecutingCount = 0;
		for(int i = 0;i < jsonDatas.size();i++){
			JsonObject js = (JsonObject)jsonDatas.get(i);
			String rs = GsonUtil.getString(js, "runResult", "");
			if(StringUtils.equals(GsonUtil.getString(js, "runResult", ""), InterfaceRunResult.Faild.ValueCode)){
				faildCount = GsonUtil.getInt(js, "id",0);
			}
			if(StringUtils.equals(GsonUtil.getString(js, "runResult", ""), InterfaceRunResult.Success.ValueCode)){
				successCount = GsonUtil.getInt(js, "id",0);
			}
			
			if(StringUtils.equals(GsonUtil.getString(js, "runResult", ""), InterfaceRunResult.Running.ValueCode)){
				ExecutingCount = GsonUtil.getInt(js, "id",0);
			}
		}
		int allCount = Math.addExact(Math.addExact(faildCount, successCount),ExecutingCount);
		NumberFormat num = NumberFormat.getPercentInstance();
		num.setMaximumIntegerDigits(3);
		num.setMaximumFractionDigits(2);
		String errorRate = null;
		if(allCount==0){
			errorRate = "0%";
		}else{
			double errorData = (double)faildCount/allCount;
			errorRate = num.format(errorData);
		}
		
		return errorRate;
	}
	
	private static FastDateFormat fastDateFormat1 = FastDateFormat.getInstance(Constants.DATETIME_PATTERN_1);
	
	//统计查询功能
	/**
	 * 统计获取十二个小时内的作业执行所消耗的时间
	 * @param nodeId 类型:String 待统计的节点ID
	 * @return	类型:String 返回的节点统计时间数据
	 */
		@RequestMapping(value = "/search/findTwelveHourAgoTime", produces = "application/json")
		@RequiresPermissions(value = { "nodeRunStatistics:view" })
		public String findTwelveHourAgoTime(String nodeId) throws ParseException {
			/*Date	beginOfRunEndTime = fastDateFormat1.parse("2015-11-12 09:30:02");
			 Date	endOfRunEndTime = fastDateFormat1.parse("2015-11-12 21:49:21");*/
			Calendar calendar = Calendar.getInstance();
			calendar.add(Calendar.HOUR_OF_DAY, -12);
			Date now = new Date();
			Date beginOfRunEndTime = DateUtils.truncate(calendar.getTime(),Calendar.SECOND);
			
			//String b1 = fastDateFormat1.format(beginOfRunEndTime);
			
			Date endOfRunEndTime = DateUtils.ceiling(now, Calendar.SECOND);
			
			//String b2 = fastDateFormat1.format(endOfRunEndTime);
			
			CriteriaBuilder cb = entityManager.getCriteriaBuilder();
			CriteriaQuery<Tuple> cq = cb.createTupleQuery();
			
			// 构建FROM和JOIN部分
			Root<InterfaceExecutionResult> rootInterfaceExecutionResult = cq.from(InterfaceExecutionResult.class);/*
			Join<InterfaceExecutionResult, KettleSlaveServer> joinKettleSlaveServer = rootInterfaceExecutionResult.join("client");*/
			Root<KettleSlaveServer> rootKettleSlaveServer = cq.from(KettleSlaveServer.class);
			// 构建WHERE部分
			List<Predicate> predicatesList = new ArrayList<>();
			if(StringUtils.isNotBlank(nodeId)){
				predicatesList.add(cb.equal(rootInterfaceExecutionResult.get("slaveServerId"), nodeId));
				predicatesList.add(cb.equal(rootKettleSlaveServer.get("id"), nodeId));
			}
			
			predicatesList.add(cb.between(rootInterfaceExecutionResult.get("runBeginTime"), beginOfRunEndTime, endOfRunEndTime));
			cq.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
			
			// 构建GROUP BY部分
			//cq.groupBy(rootInterfaceExecutionResult.get("runResult"), rootInterfaceExecutionResult.get("runResult"));
			
			// 构建SELECT部分
			cq.multiselect(
					rootInterfaceExecutionResult.get("runEndTime").alias("runEndTime"),
					rootInterfaceExecutionResult.get("runTimes").alias("runTimes"));

			// 执行查询
			TypedQuery<Tuple> q = entityManager.createQuery(cq);
			List<Tuple> queryResult = q.getResultList();
			
			// 按整点来统计运行时长
			Map<Date, Integer> totalRunTimeInHours = new HashMap<>();
			Map<Date, Integer> totalJobRunTimesInHours = new HashMap<>();
			for (Tuple tuple : queryResult) {
				Date runEndTime = tuple.get("runEndTime", Date.class);
				Integer runTimes = tuple.get("runTimes", Integer.class);
				if(runEndTime != null){
					System.out.println("null"+runTimes);
				
					runEndTime = DateUtils.ceiling(runEndTime, Calendar.HOUR_OF_DAY);
					
					Integer totalRunTimeInHour = totalRunTimeInHours.get(runEndTime);
					Integer totalJobRunTimesInHour = totalJobRunTimesInHours.get(runEndTime);
					if(totalRunTimeInHour == null){
						totalRunTimeInHour = 0;
						totalJobRunTimesInHour = 0;
					}
					if(runTimes != null){
						totalRunTimeInHour += runTimes;
						totalJobRunTimesInHour += 1;
					}
					totalRunTimeInHours.put(runEndTime, totalRunTimeInHour);
					totalJobRunTimesInHours.put(runEndTime, totalJobRunTimesInHour);
					
				}
			}
			
			JsonArray jsonDatas = new JsonArray();
			
			// 修正时间点，使结果的数量刚好等于统计时间段内的小时数
			Hours hoursBetween = Hours.hoursBetween(new DateTime(beginOfRunEndTime), new DateTime(endOfRunEndTime));
			Date timePoint = DateUtils.ceiling(beginOfRunEndTime, Calendar.HOUR_OF_DAY);
			for(int i = 1; i <= hoursBetween.getHours(); i += 1){
				
				Integer totalRunTimeInHour = totalRunTimeInHours.get(timePoint);
				Integer totalJobRunTimesInHour = totalJobRunTimesInHours.get(timePoint);
				if(totalRunTimeInHour == null){
					totalRunTimeInHour = 0;
					totalJobRunTimesInHour = 0;
				}
				DecimalFormat df = new DecimalFormat("0.00");
				double runTime = 0;
				if(totalJobRunTimesInHour != 0){
					runTime = (double)totalRunTimeInHour/totalJobRunTimesInHour;
				}else{
					runTime = 0;
				}
				JsonObject jo = new JsonObject();
				jo.addProperty("runEndTime", fastDateFormat1.format(timePoint));
				jo.addProperty("runTime", df.format(runTime));
				//jo.addProperty("runTime", totalRunTimeInHour);
				//jo.addProperty("jobRunTimes", totalJobRunTimesInHour);
				jsonDatas.add(jo);
				
				timePoint = DateUtils.addHours(timePoint, 1);
			}
			
			JsonObject jsonResult = new JsonObject();
			jsonResult.add("content", jsonDatas);
			return jsonResult.toString();
		}
}
